#!/usr/bin/python2.5
# Copyright (C) 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Editor of stop locations in GTFS feed.
#
# This is an extension of schedule_viewer.py, which allows editing
# of stop location usig drag'n'drop.
# You must provide a Google Maps API key.
#
# Usage:
# location_editor.py --key `cat key` --port 8765 --feed_filename feed.zip

import schedule_viewer, urlparse, urllib, re
from transitfeed import *
import cgi

class ScheduleEditorRequestHandler(schedule_viewer.ScheduleRequestHandler):

  def do_POST(self):
    scheme, host, path, x, params, fragment = urlparse.urlparse(self.path)
    parsed_params = {}
    for k in params.split('&'):
      k = urllib.unquote(k)
      if '=' in k:
        k, v = k.split('=', 1)
        parsed_params[k] = unicode(v, 'utf8')
      else:
        parsed_params[k] = ''

    if path == '/':
      return self.handle_GET_home()

    m = re.match(r'/post/([a-z]{1,64})', path)
    if m:
      handler_name = 'handle_POST_%s' % m.group(1)
      handler = getattr(self, handler_name, None)
      if callable(handler):
        return self.handle_json_wrapper_POST(handler, parsed_params)

  def handle_json_wrapper_POST(self, handler, parsed_params):
    """Call handler and output the return value in JSON."""
    schedule = self.server.schedule
    result = handler(parsed_params)
    content = schedule_viewer.ResultEncoder().encode(result)
    self.send_response(200)
    self.send_header('Content-Type', 'text/plain')
    self.send_header('Content-Length', str(len(content)))
    self.end_headers()
    self.wfile.write(content)

  def handle_POST_shapes(self, params):
    """parse data and store it in the database"""
    schedule = self.server.schedule
    print "inside post handle"
    form = cgi.FieldStorage(
                            fp=self.rfile,
                            headers=self.headers,
                            environ={'REQUEST_METHOD':'POST',
                            'CONTENT_TYPE':self.headers['Content-Type'],
                            })
    id = form['tripid'].value
    print id
    points = form.getlist('points[]')
    print points
    schedule.UpdateShape(id, points)
    
  def handle_json_GET_getgtfsfeed(self, params):
    """parse data and store it in the database"""
    schedule = self.server.schedule
    schedule.SaveToFeedFile()
    return ['done']

  def handle_json_GET_setstoplocation(self, params):
    """update stop latlng"""
    schedule = self.server.schedule
    id = params.get('id', None)
    lat = params.get('lat', None)
    lng = params.get('lng', None)
    routeId = params.get('routeid', None)
    schedule.UpdateStop(id, lat, lng, routeId)
    return ['1']


  def handle_json_GET_agency(self, params):
    schedule = self.server.schedule;
    agenciesList = schedule.GetAgencyList();
    agencies = []
    for agency in agenciesList:
      agencies.append({
                      'id': agency.agency_id,
                      'name': agency.agency_name,
                      'url': agency.agency_url,
                      'timezone': agency.agency_timezone,
                      'lang': agency.agency_lang,
                      'phone': agency.agency_phone
                      })
    return agencies

  def handle_json_GET_routesbyaid(self, params):
    schedule = self.server.schedule;
    id = params.get('aid', None)
    routes = []
    if id is not None:
      for route in schedule.routes.values():
        try:
          if route.agency_id:
            pass
        except:
          continue
        if id == "0" or id == route.agency_id:
          routes.append({
                        'id': route.route_id,
                        'shortName': route.route_short_name,
                        'longName': route.route_long_name,
                        'type': route.route_type,
                        'aid': route.agency_id,
                        'desc': route.route_desc,
                        'url': route.route_url,
                        'color': route.route_color,
                        'textColor': route.route_text_color
                        })
    return routes

  def handle_json_GET_tripsbyrid(self, params):
    schedule = self.server.schedule;
    id = params.get('rid', None)
    route = schedule.GetRoute(id)
    if not route:
      self.send_error(404)
      return
    ret = []
    for trip in route._trips:
      ret.append({'id': trip.trip_id, 'headsign': trip.trip_headsign, 
                 'serviceId': trip.service_id, 'direction': trip.direction_id,
                 'blockId': trip.block_id, 'serviceId': trip.service_id,
                 'shapeId': trip.shape_id, 'shapeDesc': trip.shape_desc,
                 'startTime': trip.start_time
                 })
    return ret

  def handle_json_GET_tostation(self, params):
    schedule = self.server.schedule
    stop_id = params.get('sid')
    stop = schedule.GetStop(stop_id)
    trip = schedule.GetTrip(params.get('tid'))
    sequence = params.get('seq')
    max_id = 0
    for s in schedule.GetStopList():
      if(int(s.stop_id) > max_id):
        max_id = int(s.stop_id)
    max_id += 1
    query = stop.toStationQuery(max_id)
    cursor = schedule._connection.cursor()
    cursor.execute(query)
    stop = stop.toStation(max_id)
    schedule.AddStopObject(stop)
    schedule.stops[unicode(stop.stop_id)]
    query = trip.ReplaceStopTimeObject(stop_id, max_id, sequence, schedule)
    return max_id

  def handle_json_GET_stoplatlng(self, params):
    schedule = self.server.schedule
    id = params.get('id')
    lat = params.get('lat')
    lng = params.get('lng')
    schedule.stops[id].stop_lat = lat;
    schedule.stops[id].stop_lon = lng;
    schedule.UpdateStopLatLng(id, lat, lng)
    

  def handle_json_GET_stopsbytid(self, params):
    """return origin shape data for a certain shape"""
    schedule = self.server.schedule
    try:
      trip = schedule.GetTrip(params.get('tid'))
    except KeyError:
      # if a non-existent trip is searched for, the return nothing
      return
    ret = []
    for stoptime in trip.GetStopTimes():
      ret.append({'atime': stoptime.arrival_time, 'dtime': stoptime.departure_time,
                 'sid': stoptime.stop_id, 'sequence': stoptime.stop_sequence,
                 'sname': stoptime.stop.stop_name, 'slat': stoptime.stop.stop_lat,
                 'slon': stoptime.stop.stop_lon, 'spid': stoptime.stop.parent_station})

    return ret

  def handle_json_GET_stoptimesinsert(self, params):
    schedule = self.server.schedule
    stop_id = params.get('sid')
    trip = schedule.GetTrip(params.get('tid'))
    sequence = params.get('seq')
    lat = params.get('lat')
    lng = params.get('lng')
    stop = schedule.GetStop(stop_id)
    max_id = 0
    for s in schedule.GetStopList():
      if(int(s.stop_id) > max_id):
        max_id = int(s.stop_id)
    max_id += 1
    query = stop.insertStopQuery(max_id, lat, lng)
    print "insert stop", query
    cursor = schedule._connection.cursor()
    cursor.execute(query)
    stop = stop.toStop(max_id, lat, lng)
    schedule.AddStopObject(stop)
    schedule.stops[unicode(stop.stop_id)]
    trip.InsertStopTimeObject(stop_id, max_id, sequence, schedule)
    return max_id


  def handle_json_GET_tostationbyshape(self, params):
    schedule = self.server.schedule
    route_id = params.get('rid')
    stop_id = params.get('sid')
    shape_id = params.get('id')
    sequence = params.get('seq')
    stop = schedule.GetStop(stop_id)
    max_id = 0
    for s in schedule.GetStopList():
      if(int(s.stop_id) > max_id):
        max_id = int(s.stop_id)
    max_id += 1
    query = stop.toStationQuery(max_id)
    cursor = schedule._connection.cursor()
    cursor.execute(query)
    stop = stop.toStation(max_id)
    schedule.AddStopObject(stop)
    schedule.stops[unicode(stop.stop_id)]

    Shape.ReplaceGroupStop(shape_id, route_id, stop_id, max_id, sequence, schedule)
    return max_id


  def handle_json_GET_stopinsertbyshape(self, params):
    schedule = self.server.schedule
    route_id = params.get('rid')
    stop_id = params.get('sid')
    shape_id = params.get('id')
    sequence = params.get('seq')
    lat = params.get('lat')
    lng = params.get('lng')
    stop = schedule.GetStop(stop_id)
    max_id = 0
    for s in schedule.GetStopList():
      if(int(s.stop_id) > max_id):
        max_id = int(s.stop_id)
    max_id += 1
    query = stop.insertStopQuery(max_id, lat, lng)
    print "insert stop", query
    cursor = schedule._connection.cursor()
    cursor.execute(query)
    stop = stop.toStop(max_id, lat, lng)
    schedule.AddStopObject(stop)
    schedule.stops[unicode(stop.stop_id)]

    Shape.AddGroupStop(shape_id, route_id, max_id, sequence, schedule)
    return max_id

  def handle_json_GET_stopreplacebyshape(self, params):
    schedule = self.server.schedule
    route_id = params.get('rid')
    stop_id = params.get('sid')
    shape_id = params.get('id')
    sequence = params.get('seq')
    new_stop_id = params.get('nid')
    Shape.ReplaceGroupStop(shape_id, route_id, stop_id, new_stop_id, sequence, schedule)
    return 1

  def handle_json_GET_oldstopinsertbyshape(self, params):
    schedule = self.server.schedule
    route_id = params.get('rid')
    stop_id = params.get('sid')
    shape_id = params.get('id')
    sequence = params.get('seq')
    Shape.AddGroupStop(shape_id, route_id, stop_id, sequence, schedule)
    
    #trip.InsertStopTimeObject(stop_id, max_id, sequence, schedule)
    return '1'

  def handle_json_GET_stopcopy(self, params):
    schedule = self.server.schedule
    stop_id = params.get('id')
    stop = schedule.GetStop(stop_id)
    max_id = 0
    for s in schedule.GetStopList():
      if(int(s.stop_id) > max_id):
        max_id = int(s.stop_id)
    max_id += 1
    query = stop.insertStopQuery(max_id, lat, lng)
    print "insert stop", query
    cursor = schedule._connection.cursor()
    cursor.execute(query)
    stop = stop.toStop(max_id, lat, lng)
    schedule.AddStopObject(stop)
    schedule.stops[unicode(stop.stop_id)]
    return max_id


  def handle_json_GET_stopremovebyshape(self, params):
    schedule = self.server.schedule
    route_id = params.get('rid')
    stop_id = params.get('sid')
    shape_id = params.get('id')
    sequence = params.get('seq')
    Shape.RemoveGroupStop(shape_id, route_id, stop_id, sequence, schedule)
    
    #trip.InsertStopTimeObject(stop_id, max_id, sequence, schedule)
    return 1



  def handle_json_GET_oldstoptimesinsert(self, params):
    schedule = self.server.schedule
    stop_id = params.get('sid')
    trip = schedule.GetTrip(params.get('tid'))
    sequence = params.get('seq')
    '''
    stop = schedule.GetStop(stop_id)
    max_id = 0
    for s in schedule.GetStopList():
      if(int(s.stop_id) > max_id):
        max_id = int(s.stop_id)
    max_id += 1
    query = stop.insertStopQuery(max_id, lat, lng)
    print "insert stop", query
    cursor = schedule._connection.cursor()
    cursor.execute(query)
    stop = stop.toStop(max_id, lat, lng)
    schedule.AddStopObject(stop)
    schedule.stops[unicode(stop.stop_id)]
    '''
    trip.InsertStopTimeObject(stop_id, stop_id, sequence, schedule)
    return stop_id

 
  def handle_json_GET_stoptimesremove(self, params):
    schedule = self.server.schedule
    sid = params.get('sid')
    tid = params.get('tid')
    seq = params.get('seq')
    trip = schedule.GetTrip(tid)
    trip.RemoveStopTimeObject(sid, seq, schedule)
    return 1

  def handle_json_GET_stoptimesremove(self, params):
    schedule = self.server.schedule
    sid = params.get('sid')
    tid = params.get('tid')
    seq = params.get('seq')
    trip = schedule.GetTrip(tid)
    trip.RemoveStopTimeObject(sid, seq, schedule)
    return 1

  def handle_json_GET_shapeexistbytid(self, params):
    """return origin shape data for a certain shape"""
    schedule = self.server.schedule
    try:
      print "shape exist by tid"
      trip = schedule.GetTrip(params.get('tid'))
    except KeyError:
      # if a non-existent trip is searched for, the return nothing
      print "shape exist by tid error"
      return [0]
    print "shape exist by tid 1"
    try:
      if trip.shape_id:
        print trip.shape_id
        shape = schedule.GetShape(trip.shape_id)
        if len(shape.points) > 0:
          return [1]
    except:
      pass
    return [0]

  def handle_json_GET_shapesbytid(self, params):
    """return origin shape data for a certain shape"""
    schedule = self.server.schedule
    try:
      print "shapes by tid"
      trip = schedule.GetTrip(params.get('tid'))
    except KeyError:
      # if a non-existent trip is searched for, the return nothing
      print "shapes by tid error"
      return
    points = []
    print "shapes by tid 1"
    try:
      if trip.shape_id:
        print trip.shape_id
        shape = schedule.GetShape(trip.shape_id)
        print shape
        for (lat, lon, dist) in shape.points:
          points.append({'lat': lat, 'lng': lon, "dist": dist})
    except:
      pass
    return points

  
  def handle_json_GET_triporiginshape(self, params):
    """return origin shape data for a certain shape"""
    print "triporiginshape"
    schedule = self.server.schedule
    try:
      trip = schedule.GetTrip(params.get('trip'))
    except KeyError:
      # if a non-existent trip is searched for, the return nothing
      return
    points = []
    try:
      if trip.shape_id:
        shape = schedule.GetOriginalShape(trip.shape_id)
        for (lat, lon, dist) in shape.points:
          points.append((lat, lon))
      else:
        time_stops = trip.GetTimeStops()
        for arr, dep, stop in time_stops:
          points.append((stop.stop_lat, stop.stop_lon))
    except:
      pass
    return points


  def handle_json_GET_shapes(self, params):
    """get data for a certain shape"""
    schedule = self.server.schedule
    try:
      trip = schedule.GetTrip(params.get('trip'))
    except KeyError:
      # if a non-existent trip is searched for, the return nothing
      return
    points = []
    if trip.shape_id:
      shape = schedule.GetShape(trip.shape_id)
      for (lat, lon, dist) in shape.points:
        points.append((lat, lon))
    return points

  def handle_json_GET_updatestopname(self, params):
    """update name for a certain stop"""
    schedule = self.server.schedule
    id = params.get('stop', None)
    name = params.get('name', None)
    schedule.UpdateStopName(id, name)
    return 'updated'


  def AllowEditMode(self):
    return True

if __name__ == '__main__':
  schedule_viewer.main(ScheduleEditorRequestHandler)
